#include <jni.h>
#include <opencv2/opencv.hpp>
#include <string>
#include <iostream>
#include "Detector.h"
#include <codecvt>
#include <locale>
#include <android/log.h>
//
// Created by mac on 2023/4/18.
//
using namespace std;
using namespace cv;
using namespace detect;

/*Config config;
Detector *detector = Detector::GetInstance();

struct Response {
    bool Flag;
    string prompt;
};

Response Verity(Mat &SourceImage) {

    struct Response response = {false, "输入为空"};
    if (SourceImage.empty()) {
        return response;
    }
    int Prompt = detector->ComputerPixelMean(SourceImage);
    response.prompt = Prompt;
    int prompt = detector->ComputerBlurry(SourceImage);
    return response;
}*/

int status_2_int(detect::Status& status){
    int result = 0;
    result |= (status.FaceStatus & 0x0001);
    result <<= 1;
    result |= (status.Luminance & 0x0001);
    result <<= 1;
    result |= (status.Blurry & 0x0001);
    return result;
}

jobject convertCvRectToJavaRect(JNIEnv* env, const cv::Rect& rect) {
    // 1. 查找 Rect 类
    jclass rectClass = env->FindClass("android/graphics/Rect");
    if (rectClass == nullptr) return nullptr;

    // 2. 获取构造函数 (int, int, int, int)
    jmethodID constructor = env->GetMethodID(rectClass, "<init>", "(IIII)V");
    if (constructor == nullptr) return nullptr;

    // 3. 计算右下角坐标
    int left = rect.x;
    int top = rect.y;
    int right = rect.x + rect.width;
    int bottom = rect.y + rect.height;

    // 4. 创建 Java 对象
    jobject javaRect = env->NewObject(rectClass, constructor, left, top, right, bottom);
    return javaRect;
}


jstring utf8ToJString(JNIEnv* env, const std::string& utf8Str) {
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
    std::u16string utf16Str = converter.from_bytes(utf8Str);
    return env->NewString(reinterpret_cast<const jchar*>(utf16Str.c_str()), utf16Str.length());
}


jobject create_java_FaceResult(JNIEnv* env,jclass clazz,jboolean faceStatus,jboolean luminance,jboolean blurry,jstring log,cv::Rect faceRect,cv::Rect detRect){
    // 1. 获取 Java 类
    jclass resultClass = env->FindClass("com/bnq/face/FaceResult");
    if (resultClass == nullptr) {
        return nullptr; // 找不到类
    }
    // 2. 获取构造函数 (boolean, boolean, boolean, String)
    jmethodID constructor = env->GetMethodID(resultClass, "<init>", "(ZZZLjava/lang/String;Landroid/graphics/Rect;Landroid/graphics/Rect;)V");
    if (constructor == nullptr) {
        return nullptr; // 构造函数没找到
    }
    jobject resultObj = env->NewObject(resultClass, constructor, faceStatus, luminance, blurry, log,convertCvRectToJavaRect(env,faceRect),convertCvRectToJavaRect(env,detRect));
    return resultObj;
}


extern "C"
JNIEXPORT jstring JNICALL
Java_com_bnq_face_FaceHandler_getStringForNative(JNIEnv *env, jclass clazz) {
    char * str = "hello world from C";
    return env->NewStringUTF(str);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_bnq_face_FaceHandler_computerBlurry(JNIEnv *env, jclass clazz, jstring path) {
    const char * filePath = env->GetStringUTFChars(path, nullptr);
    Mat image = imread(filePath, IMREAD_COLOR);
//    Response response = Verity(image);
//    std::cout << response.prompt << std::endl;
//    string PromptBrightNess = detector.ComputerPixelMean(image);
    env->ReleaseStringUTFChars(path,filePath);
    auto status = detect::predict(image,100,210,80,0.8,0.25,70,185,306,508);
    //0 图像不可用 1 图像可用
    return env->NewStringUTF((status.FaceStatus == 1 && status.Luminance == 1 && status.Blurry == 1) ? "图像可用" : "图像不可用");
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_bnq_face_FaceHandler_computerBlurry2(JNIEnv *env, jclass clazz, jbyteArray bytes) {
    jsize  len = env->GetArrayLength(bytes);
    void *bufferPtr = env->GetPrimitiveArrayCritical(bytes, nullptr);
    auto status = detect::predict((char*)bufferPtr,len,00,210,80,0.8,0.25,70,185,306,508);
    env->ReleasePrimitiveArrayCritical(bytes,bufferPtr,JNI_ABORT);
    //0 图像不可用 1 图像可用
    return env->NewStringUTF(status.FaceStatus == 0 ? "图像不可用" : "图像可用");
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_bnq_face_FaceHandler_faceDetect(JNIEnv *env, jclass clazz, jbyteArray bytes,jint width,jint height,
                                         jdouble mini_thresh, jdouble max_thresh,
                                         jdouble blue_thresh, jdouble iou_normal, jdouble iou_inter,
                                         jdouble tlxratio, jdouble tlyratio, jdouble rbxratio,
                                         jdouble rbyratio) {
    //__android_log_print(ANDROID_LOG_ERROR,"Face","-------------native faceDetect: miniThresh=%f,maxThresh=%f,blueThresh=%f,iou_normal=%f,iou_inter=%f,tlxratio=%f,tlyratio=%f,rbxratio=%f,rbyratio=%f", mini_thresh, max_thresh,blue_thresh,iou_normal,iou_inter,tlxratio,tlyratio,rbxratio,rbyratio);
    jsize  len = env->GetArrayLength(bytes);
    void *bufferPtr = env->GetPrimitiveArrayCritical(bytes, nullptr);
    auto status = detect::predict((char*)bufferPtr,len,mini_thresh,max_thresh,blue_thresh,iou_normal,iou_inter,tlxratio,tlyratio,rbxratio,rbyratio);
    env->ReleasePrimitiveArrayCritical(bytes,bufferPtr,JNI_ABORT);
    jstring j_log = utf8ToJString(env,status.logStr);
    jobject face_result = create_java_FaceResult(env,clazz,status.FaceStatus,status.Luminance,status.Blurry,j_log,status.faceRect,status.detRect);
    //__android_log_print(ANDROID_LOG_ERROR,"Face","-------------native faceDetect: FaceStatus=%d,Luminance=%d,Blurry=%d,size:%d,faceRect(%d %d %d %d),detRect(%d %d %d %d),log=%s", status.FaceStatus, status.Luminance,status.Blurry,len,status.faceRect.x,status.faceRect.y,status.faceRect.x+status.faceRect.width,status.faceRect.y+status.faceRect.height,status.detRect.x,status.detRect.y,status.detRect.x+status.detRect.width,status.detRect.y+status.detRect.height,status.logStr.c_str());
    return face_result;
}